# This is version 1.07. The main addition planned for this version is to add Pubmed searches
# in addition to the scopus one.

import os
import sys
import re
import shutil
import time

import mechanize
import cookielib
from PyQt4 import QtCore, QtGui, Qt

from ScopusRetrieval import Ui_ScopusRetrMainWindow
from prefs_dialog import Ui_PreferencesDialog
from indexing_dialog import Ui_IndexingDialog
import reference_retrieve
import pdf_downloader
import common_tools
import pdf_index
import picture_viewer
import notes_editor_wrapper
import record_adder_wrapper

__current_version__ = 'CitationControl 1.09 beta'
__future_version__ = 'CitationControl 1.10 beta'


class StartQT4(QtGui.QMainWindow):
    '''
    The main run class.
    '''
    def __init__(self, parent=None):
        '''
        The main run file.
        1. Setup the window
        2. Size the windows correctly
        3. Initialize some variables for later use
        4. Initialize thread variables
        5. Make a new timer, start it and connect it to the download pool.
        6. Connections of different widgets and actions
        7. Add a clipboard to keep track of clipped functions.
        8. Read the configuration file to get configuration values for this session.
        9. check proxy and scopus settings.
        10. Create and maintain a progres dialog
        11. Keep a notes editor handy.
        '''

        #1. Window setup
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_ScopusRetrMainWindow()
        self.ui.setupUi(self)
        self.setWindowTitle('CitationControl (Pubmed)')
        self.ui.mainTab.setTabsClosable(True)
        self.ui.ObtainFTextButton.setText("Obtain Searchable Text (and pdfs)")
        self.ui.scopusSearchLabel.setText("Search string (keyword, a: for author, j: for journal, y: for beginYear-endYear) e.g. 'neuron a:Wilson,M y:1990-2008 j:Neuroscience' without the quotes.")
        splash_pix = QtGui.QPixmap('icons/Cctrl_cc.png')
        splash = QtGui.QSplashScreen(splash_pix, QtCore.Qt.WindowStaysOnTopHint)
        splash.setMask(splash_pix.mask())
        splash.show()
        #2. Appropriate sizing when maximizing
        self.treeWidgetSized(self.ui.treeWidget)
        #3. Variables are initialized
        self.resultSet = []
        self.number_of_threads = 5
        splash.showMessage("Initializing variables")
        self.currentSession = None
        # For new tabs
        self.tabCount = 1
        self.hlayoutCount = 1
        self.treeCount = 1
        # For previously downloaded stuff
        self.available_texts = []
        #8.
        self.config_dict = {}
        splash.showMessage("Reading configuration files")
        self.populate_configuration('../CitationControl.conf', self.config_dict)
        configText = open('../CitationControl.conf').readlines()
        try:
            x = open('adt').read()
            x = x[1:-1]
            import bz2
            x = bz2.decompress(x)
            self.config_dict['password'] = x
        except:
            self.config_dict['password'] = ''
        configText = [x for x in configText if not x.startswith('#')]
        for i in configText:
            if not i.strip() == '':
                vals = i.split()
                header = vals[0].strip(); value = vals[1].strip()
                self.config_dict[header] = value
        self.make_icons()       
        #4. Initializing thread variables.
        self.threadCount = 0
        self.threadpool = {}
        self.pdf_download_pool = []
        self.current_pdf_threads = []
        self.openWindows = []
        self.done_threads = 0
        self.started_threads = 0
        self.threads_done = True

        #5. Timer setup
        self.timer = QtCore.QTimer()
        self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.timedDownload)
        self.timer.start(1000)
        
        #6. Connections
        self.make_connections()
        
        #7.
        self.clipboard = []
        
        #9.
        splash.clearMessage()
        splash.showMessage("Checking internet connection")
        if not common_tools.isonline():
            QtGui.QMessageBox.information (self, 'Check internet connection',
                                           "Just pinged google and got no response. \
                                           Check your internet connection",
                                           QtGui.QMessageBox.Ok)
        splash.clearMessage()
        splash.showMessage("Checking for updates")
        future_version = __future_version__.replace(' ', '%20')
        future_site = 'http://sourceforge.net/projects/citationcontrol/files/' + future_version + '/'
        if common_tools.updates_available(future_site):
            QtGui.QMessageBox.information (self, 'Found updates',
                                           "An updated version (%s) is available. Please check www.citationcontrol.sourceforge.net for details." % __future_version__,
                                           QtGui.QMessageBox.Ok)
        splash.clearMessage()
        if os.path.isfile('../Contributed.txt'):
            pass
        else:
            QtGui.QMessageBox.information (self, 'Friendly contribution reminder',
                                           "If you have contributed towards the development of this project, Thanks.\nIf not and you would like to, please choose the 'Donate' Button at the website.\n\nThis is just a friendly non-intrusive message.\n(No function of the software is affected. CitationControl will always remain free)\n\n You can disable this message at any time by creating a new file called 'Contributed.txt' in the folder containing the configuration files (CitationControl.conf and CitationControl_default.conf).",
                                           QtGui.QMessageBox.Ok, QtGui.QMessageBox.Cancel)
        #10.
        import progress_dialog
        self.prog_window = QtGui.QDialog(self)
        self.prog_dialog = progress_dialog.Ui_Dialog()
        self.prog_dialog.setupUi(self.prog_window)
        self.prog_window.hide()

        self.img_window = QtGui.QDialog(self)
        self.img_dialog = progress_dialog.Ui_Dialog()
        self.img_dialog.setupUi(self.img_window)
        self.img_dialog.label.setText('Extracting images from the pdf file.')
        self.img_window.hide()

        self.initialize_notes_window()


        self.record_window = record_adder_wrapper.RecordWindow(self)
        self.record_window.hide()
        self.connect(self.record_window, QtCore.SIGNAL('recordChanged'),
                     self.update_done)
        self.get_downloaded_file_info()
        self.read_tags()
        splash.hide()
        

    def make_icons(self):
        '''
        Make icons for different functions.
        '''
        self.done_icon = QtGui.QIcon()
        self.tabDone_icon = QtGui.QIcon()
        self.tabWorking_icon = QtGui.QIcon()
        self.error_icon = QtGui.QIcon()
        self.notDone_icon = QtGui.QIcon()
        self.working_icon = QtGui.QIcon()
        self.help_icon = QtGui.QIcon()
        self.help_icon.addPixmap(QtGui.QPixmap("%shelp.png" % self.config_dict['iconLocation']), 
                                 QtGui.QIcon.Normal, QtGui.QIcon.On)
        self.done_icon.addPixmap(QtGui.QPixmap("%sdone.png" % self.config_dict['iconLocation']), 
                                 QtGui.QIcon.Normal, QtGui.QIcon.On)
        self.notDone_icon.addPixmap(QtGui.QPixmap("%snotDone.png" % self.config_dict['iconLocation']), 
                                    QtGui.QIcon.Normal, QtGui.QIcon.On)
        self.error_icon.addPixmap(QtGui.QPixmap("%serror.png" % self.config_dict['iconLocation']), 
                                  QtGui.QIcon.Normal, QtGui.QIcon.On)
        self.working_icon.addPixmap(QtGui.QPixmap("%sworking.png" % self.config_dict['iconLocation']), 
                                    QtGui.QIcon.Normal, QtGui.QIcon.On)
        self.tabDone_icon.addPixmap(QtGui.QPixmap("%stabDone.png" % self.config_dict['iconLocation']), 
                                    QtGui.QIcon.Normal, QtGui.QIcon.On)
        self.tabWorking_icon.addPixmap(QtGui.QPixmap("%stabWorking.png" % self.config_dict['iconLocation']), 
                                       QtGui.QIcon.Normal, QtGui.QIcon.On)
                                           
    def add_data(self, lst, treeWidget, tab_location, threadnum):
        '''
        The main function that adds data into a tab. It receives the list for the tab, its treewidget and
        the tab location as arguments.
        It does the following.
        1. Adds the list to self.resultSet at the tab location if that still exists. If not, then quit.
           The only caveat here is this. If a search is started, but the tab is closed, the search is still
           done and results obtained.
        2. Add some actions to the treeWidget and
        3. load the list into the treeWidget. Remember that the first
           element in the list is just the title.
        4. Changes the color of tab header to indicate done.
        '''
        #1.
        try:
            self.resultSet[tab_location] = lst
        except:
            return
        #2. 
        treeWidget.clear()
        details_titles = ['Title',
                          'Authors', 'Year', 'Journal', 'Issue', 'Pages']
        treeWidget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        treeWidget.addActions([self.showAvailableAction, self.editRecord, self.exportBibAction,
                               self.menuSeparator4,
                               self.tagAction, self.removeTagAction, self.editTagAction, self.menuSeparator1,
                               self.addToClipboard, self.addNotes, self.showClipboard, self.menuSeparator2,
                               self.deleteStoredTextAction, self.menuSeparator3,
                               self.getPdfAction, self.downloadPdfAction, self.showPdfImagesAction])
        #treeWidget.setSortingEnabled(True)

        #3.
        for num, cite in enumerate(lst[1:]):
            eid_checkval = cite['EID']
            a = QtGui.QTreeWidgetItem(treeWidget)
            a.setIcon(7, self.notDone_icon)
            a.setHidden(False)
            cite['Tags'] = cite.get('Tags', '')
            cite['PMC'] = cite.get('PMC', '')
            if cite['PMC'].strip() == '':
                a.setIcon(7, self.error_icon)
            if os.path.isfile('%s%s.txt' % (self.config_dict['storageLocation'], eid_checkval)):
                a.setIcon(7, self.done_icon)
                detail = eval(open('%s%s.dxt' % (self.config_dict['storageLocation'], eid_checkval)).read())
                a.setText(6, detail['Tags'])
            for num, detail in enumerate(details_titles):
                a.setText(num, cite[detail])

        #4.
        orig_tab_text = self.ui.mainTab.tabText(tab_location)
        self.ui.mainTab.setTabIcon(tab_location, self.tabDone_icon)

    def search_scopus_button_clicked(self):
        '''
        When the scopus search button is clicked:
        1. Get the text to search, make up a waiting text
           for treewidgets and a statusbar msg_value
        2. Get the treeWidget where the final data goes into
           and the location of the tab using make_new_tab.
        3. Create a new thread for scopus search, add it to the threadpool and start it.
        
        '''
        self.ui.textEdit.clear()
        self.ui.textEdit.setHtml('Searching pubmed for results.')
        #1. 
        search_text = str(self.ui.scopusSearchLineEdit.text())
        msg_value = 'Pubmed search for %s.' % search_text
        waiting_text = "Waiting: %s." % msg_value
        #2.
        treeWidget, tabLoc = self.make_new_tab(search_text, waiting_text)
        self.ui.mainTab.setTabIcon(tabLoc, self.tabWorking_icon)
        #3.
        t = pdf_downloader.PUBMEDSearchThread(treeWidget, self.config_dict)
        self.threadpool[self.threadCount] = t
        self.connect(self.threadpool[self.threadCount],
                     QtCore.SIGNAL('resultsObtained'), self.add_data)
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage(msg_value, 3000)
        self.threadpool[self.threadCount].start_process(search_text, tabLoc, self.threadCount)
        self.threadCount += 1

    def obtain_citations(self):
        '''
        Obtains citations for a selected article.
        1. Get a handle to the current tree. Also get the number of selected items.
        2. Make sure that there is only one item selected. Else, give an error message.
        3. From resultSet, get the title and scopus record of the article. This is where the number
        of citations will be given.
        4. Using a message and waiting value, make a new tab.
        5. Start a new thread for getting citations.
        '''
        #1. 
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()

        #2. 
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        #3.
        selected_item = selected_items[0]
        row_index = currentTreeWidget.indexFromItem(selected_item).row()
        record_detail = self.resultSet[current_tab_index][1:][row_index]
        title = record_detail['Title']
        pmid = record_detail['PMRecord']
        #4.
        msg_value = "(C): %s" % (title)
        waiting_text = "Waiting: %s." % msg_value
        treeWidget, tabLoc = self.make_new_tab(msg_value, waiting_text)
        self.ui.mainTab.setTabIcon(tabLoc, self.tabWorking_icon)
        #5.
        t = pdf_downloader.CitationSearchThread(treeWidget, self.config_dict)
        self.threadpool[self.threadCount] = t
        self.connect(self.threadpool[self.threadCount],
                     QtCore.SIGNAL('resultsObtained'), self.add_data)
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage(waiting_text, 2000)
        self.threadpool[self.threadCount].start_process(msg_value, pmid, tabLoc, self.threadCount)
        self.threadCount += 1

    def obtain_references(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        selected_item = selected_items[0]
        row_index = currentTreeWidget.indexFromItem(selected_item).row()
        record_detail = self.resultSet[current_tab_index][1:][row_index]
        title = record_detail['Title']
        pmid = record_detail['PMRecord']
        msg_value = "(Ref): %s" % (title)
        waiting_text = "Waiting: %s." % msg_value
        treeWidget, tabLoc = self.make_new_tab(msg_value, waiting_text)
        self.ui.mainTab.setTabIcon(tabLoc, self.tabWorking_icon)
        t = pdf_downloader.ReferenceSearchThread(treeWidget, self.config_dict)
        self.threadpool[self.threadCount] = t
        self.connect(self.threadpool[self.threadCount],
                     QtCore.SIGNAL('resultsObtained'), self.add_data)
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage(waiting_text, 2000)
        self.threadpool[self.threadCount].start_process(msg_value, pmid, tabLoc, self.threadCount)
        self.threadCount += 1

    def obtain_related(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        selected_item = selected_items[0]
        row_index = currentTreeWidget.indexFromItem(selected_item).row()
        record_detail = self.resultSet[current_tab_index][1:][row_index]
        title = record_detail['Title']
        pmid = record_detail['PMRecord']
        msg_value = "(Rel): %s" % (title)
        waiting_text = "Waiting: %s." % msg_value
        treeWidget, tabLoc = self.make_new_tab(msg_value, waiting_text)
        self.ui.mainTab.setTabIcon(tabLoc, self.tabWorking_icon)
        t = pdf_downloader.RelatedSearchThread(treeWidget, self.config_dict)
        self.threadpool[self.threadCount] = t
        self.connect(self.threadpool[self.threadCount],
                     QtCore.SIGNAL('resultsObtained'), self.add_data)
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage(waiting_text, 2000)
        self.threadpool[self.threadCount].start_process(msg_value, pmid, tabLoc, self.threadCount)
        self.threadCount += 1
        
    def obtainFTextButton_clicked(self):
        # There might be many tabs and trees. It is important to get the current one
        self.update_available_texts()
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        selected_indices = []
        for item in selected_items:
            selection_row = currentTreeWidget.indexFromItem(item).row()
            selected_indices += [selection_row]
            
        for i in selected_indices:
            self.change_status(i,current_tab_index, "working")
            selection_eid = self.resultSet[current_tab_index][1:][i]['EID']
            if selection_eid in self.available_texts:
                self.change_status(i, current_tab_index, "done")
                continue
            download_details = {}
            download_details['selection_row'] = i
            download_details['current tab index'] = current_tab_index
            download_details['list'] = self.resultSet[current_tab_index][1:]
            temp_pool = [[[current_tab_index], download_details]]
            self.pdf_download_pool += temp_pool

    def update_available_texts(self):
        self.available_texts = os.listdir(self.config_dict['storageLocation'])
        self.available_texts = [x[:-4] for x in self.available_texts if x.endswith('.txt')]
        
    def timedDownload(self):
        '''
        Run whenever there is a timer tick.
        If there are no threads in the pool, then do nothing.
        If there are less that the number of threads, then run these threads.
        If more, then do the first x number of threads, then the next and so on.
        '''
        if self.threads_done:
            if len(self.pdf_download_pool) == 0:
                return
            if len(self.pdf_download_pool) <= self.number_of_threads:
                temp_pdf_download_pool = [x[1] for x in self.pdf_download_pool]
                self.current_pdf_threads = temp_pdf_download_pool[:]
                self.run_pdf_downloads(self.current_pdf_threads)
                self.pdf_download_pool = []
                self.threads_done = False
            if len(self.pdf_download_pool) > self.number_of_threads:
                temp_pdf_download_pool = self.pdf_download_pool[:self.number_of_threads]
                temp_pdf_download_pool = [x[1] for x in temp_pdf_download_pool]
                self.current_pdf_threads = temp_pdf_download_pool
                self.pdf_download_pool = self.pdf_download_pool[self.number_of_threads:]
                self.run_pdf_downloads(self.current_pdf_threads)
                self.threads_done = False

    def run_pdf_downloads(self, cur_pdfs):
        if self.threads_done:
            for i in cur_pdfs:
                t = pdf_downloader.PDFDownloadThread(self.config_dict)
                self.threadpool[self.threadCount] = t
                self.connect(self.threadpool[self.threadCount],
                             QtCore.SIGNAL("updateImage"), self.change_status)
                self.connect(self.threadpool[self.threadCount],
                             QtCore.SIGNAL("done"), self.done_thread)
                self.started_threads += 1
                self.threadpool[self.threadCount].start_process(i['selection_row'],
                                                         i['current tab index'],
                                                         i['list'],
                                                         self.threadCount)
                self.threadCount += 1
                
    def done_thread(self, threadnum):
        self.done_threads += 1
        if self.done_threads == self.started_threads:
            self.started_threads = 0
            self.done_threads = 0
            self.threads_done = True
            
    def tabClosed(self, int):
        for i in range(self.ui.mainTab.count()):
            widg = self.ui.mainTab.widget(i)
            treeWidg = None
            for j in widg.children():
                if 'treeWidget' in j.objectName():
                    treeWidg = j
            if treeWidg.topLevelItemCount() == 1:
                itemText = treeWidg.topLevelItem(0).text(0)
                if 'Waiting:' in itemText:
                    QtGui.QMessageBox.information (self, 'Wait for list updates.',
                                                   """
                                                   One of the tabs is still being updated.
                                                   If this is slow, it could be due to a lot
                                                   of open tabs
                                                   or if there are > 200 citations or references
                                                   in a tab.
                                                   
                                                   You can avoid this in the future by
                                                   reducing the number of tabs or
                                                   allowing tabs to finish refreshing
                                                   before starting new searches.""",
                                                   QtGui.QMessageBox.Ok)
                    return
        if len(self.resultSet) > 0:
            self.ui.mainTab.removeTab(int)
            self.resultSet.pop(int)
            windowAction = self.openWindows[int]
            self.goToMenu.removeAction(windowAction)
            self.openWindows.pop(int)
            self.pdf_download_pool = [x for x in self.pdf_download_pool if not x[0][0] == int]
            
    def add_to_clipboard(self):
        ''' Just add to a list which will be saved throughout this session.
        '''
        currentTreeWidget, current_ind = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0: return
        for i in selected_items:
            selection_row = currentTreeWidget.indexFromItem(i).row()
            selection_record = self.resultSet[current_ind][selection_row+1]
            self.clipboard += [selection_record]

    def clear_clipboard(self):
        ''' Clear the clipboard
        '''
        self.clipboard = []
        
    def show_clipboard(self):
        '''
        Just show everything that was saved.
        '''
        self.ui.textEdit.clear()
        output = ['<b> CitationControl Clipboard: </b>']
        for i in self.clipboard:
            try:
                title = i['Title']
                authors = i['Authors']
                journal = i['Journal']
                yr = i['Year']            
                issue = i['Issue']
                pages = i['Pages']
                output_val = '%s, <i>%s</i>, <b><font color="#330000">%s</font></b>. %s; %s: %s.' % (
                    authors, title, journal, yr, issue, pages)
                output += [output_val]
            except:
                output += [unicode('<b>Selected text: </b>') + unicode(i)]
        clip_html = QtCore.QStringList()
        for i in output:
            clip_html.append(i)
        clip_html = clip_html.join('<br><br>')
        self.ui.textEdit.setHtml(clip_html)
        
    def fullTextSearchAuto(self):
        '''
        Automatically searches the full text when characters are entered.
        '''
        currentTreeWidget, current_ind = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) > 1: return
        if len(selected_items) == 0: return
        search_term = str(self.ui.lineEdit.text()).strip()
        if len(search_term.split()) > 1: return
        if not search_term == '':
            self.fullTextSearch()
        
    def fullTextSearch(self):
        search_term = str(self.ui.lineEdit.text()).strip()
        if search_term == '':
            QtGui.QMessageBox.information (self, 'No Search Term',
                                           'A search term needs to be entered', QtGui.QMessageBox.Ok)
            return
        self.ui.textEdit.clear()
        currentTreeWidget, current_ind = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            self.fulltextSearchMultiple(search_term)
            return
        selection_row = currentTreeWidget.indexFromItem(selected_items[0]).row()
        # Get the actual record offset by 1
        selection_record = self.resultSet[current_ind][selection_row+1]
        eid_of_selection = selection_record['EID']
        try:
            fulltext = open('%s%s.txt' % (self.config_dict['storageLocation'], eid_of_selection)).read()
        except:
            QtGui.QMessageBox.information (self, 'Non-existant record',
                                           'The full text has not been downloaded.', QtGui.QMessageBox.Ok)
            return
        fulltext = fulltext.split('\n')
        and_split = search_term.split(' (and) ')
        or_split = search_term.split(' (or) ')
        newText = []
        if (len(and_split) > 1) and (len(or_split) > 1):
            QtGui.QMessageBox.warning (self, 'Chained operators',
                                           'Only one "and" or "or" can be searched at this time.',
                                           QtGui.QMessageBox.Ok)
            return
        elif len(and_split) > 1:
            newText = self.return_operator_test(fulltext, and_split, 'and')
            newText = '<br><br>'.join(newText)
        elif len(or_split) > 1:
            newText = self.return_operator_test(fulltext, or_split, 'or')
            newText = '<br><br>'.join(newText)
        else:
            newText = [x for x in fulltext if str(search_term).lower() in x.lower()]
            newText = '<br><br>'.join(newText)
            strongText = '<b><font color="#330000">%s</font></b>' % search_term
            newText = newText.replace(search_term, strongText)
        if newText == '': newText = 'String "%s" absent in this article' % search_term
        self.ui.textEdit.clear()
        self.ui.textEdit.setHtml(newText)

    def return_operator_test(self, fulltxt, opArray, oper):
        '''
        A utility function to check for ands and ors.
        '''
        newText = []
        opArray = [x.lower() for x in opArray]
        opArrays = ['"%s"' % x.strip() for x in opArray]
        opArrays = (' in x.lower() %s ' % oper).join(opArrays)
        opArrays = opArrays + ' in x.lower()'
        for x in fulltxt:
            if eval(opArrays):
                for i in opArray:
                    op_val = re.compile(i, re.IGNORECASE)
                    x = op_val.sub('<b><font color="#330000">%s</font></b>' % i, x)
                newText += [x]
        return newText
            
    def fulltextSearchMultiple(self, search_term):
        self.ui.textEdit.clear()
        currentTreeWidget, current_ind = self.getTreeWidget_index()
        for i in range(currentTreeWidget.topLevelItemCount()):
            item = currentTreeWidget.topLevelItem(i)
            item.setBackgroundColor(0, QtGui.QColor(QtCore.Qt.white))
        selected_items = currentTreeWidget.selectedItems()
        # This will need to be dried.
        and_split = search_term.split(' (and) ')
        or_split = search_term.split(' (or) ')        
        for i in selected_items:
            newText = []
            currentTreeWidget.setItemSelected(i, False)
            selection_row = currentTreeWidget.indexFromItem(i).row()
            # Get the actual record offset by 1
            selection_record = self.resultSet[current_ind][selection_row+1]
            eid_of_selection = selection_record['EID']
            try:
                fulltext = open('%s%s.txt' % (self.config_dict['storageLocation'], eid_of_selection)).read()
            except:
                continue
            fulltext = fulltext.split('\n')
            if len(and_split) > 1:
                newText = self.return_operator_test(fulltext, and_split, 'and')
            elif len(or_split) > 1:
                newText = self.return_operator_test(fulltext, or_split, 'or')
            else:
                newText = [x for x in fulltext if str(search_term).lower() in x.lower()]
                
            if len(newText) > 0:
                i.setHidden(False)
            else:
                i.setHidden(True)

    def make_new_tab(self, tabTitle, waitingTxt, insertAfter=None):
        if len(tabTitle) > 30: tabTitle = tabTitle[:30]
        if self.tabCount == 1:
            self.ui.mainTab.setTabText(0, tabTitle)
            self.ui.treeWidget.clear()
            treeWidget = self.ui.treeWidget
            self.tabCount += 1
        else:
            self.tabCount += 1
            self.hlayoutCount += 1
            self.treeCount += 1
            tab = QtGui.QWidget()
            tab.setObjectName("tab%s" % self.tabCount)
            hlayout = QtGui.QHBoxLayout(tab)
            hlayout.setObjectName("horizontalLayout%s" % self.hlayoutCount)
            hlayout2 = QtGui.QHBoxLayout()
            hlayout2.setContentsMargins(-1, 1, -1, -1)
            self.hlayoutCount += 1
            hlayout2.setObjectName("horizontalLayout%s" % self.hlayoutCount)
            treeWidget = QtGui.QTreeWidget(tab)
            treeWidget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
            treeWidget.setObjectName("treeWidget%s" % self.treeCount)
            self.treeWidgetSized(treeWidget)
            self.connect(treeWidget, QtCore.SIGNAL('itemSelectionChanged()'), self.show_selection_status)
            treeWidget.itemDoubleClicked.connect(self.item_double_clicked)
            header_titles = ['Title',
                             'Authors', 'Year', 'Journal', 'Issue', 'Pages', 'Tags', 'Process']
            for num, title in enumerate(header_titles):
                treeWidget.headerItem().setText(num,
                                                QtGui.QApplication.translate(
                                                    "ScopusRetrMainWindow", title, None,
                                                    QtGui.QApplication.UnicodeUTF8))
            hlayout.addWidget(treeWidget)
            if not insertAfter:
                self.ui.mainTab.addTab(tab, tabTitle)
            else:
                self.ui.mainTab.insertTab(insertAfter, tab, tabTitle)
        tab_index_location = len(self.resultSet)
        self.resultSet += [False]
        a = QtGui.QTreeWidgetItem(treeWidget)
        a.setText(0, waitingTxt)
        window_menu_item = QtGui.QAction(QtGui.QIcon('%swindows.png' % self.config_dict['iconLocation']),
            tabTitle, self)
        self.openWindows.append(window_menu_item)
        window_menu_item = self.openWindows[len(self.openWindows)-1]
        
        self.goToMenu.addAction(window_menu_item)
        return treeWidget, tab_index_location

    def getTreeWidget_index(self):
        '''Returns the current tree widget and  the current index selected.'''
        current_ind = self.ui.mainTab.currentIndex()
        currentTreeWidget = None
        for i in self.ui.mainTab.currentWidget().children():
            if 'treeWidget' in i.objectName():
                currentTreeWidget = i
        return currentTreeWidget, current_ind

    def getCurrentCitation(self):
        '''
        Get details of the current Citation.
        '''
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'Multiple Selections',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        selected_item = selected_items[0]
        row_index = currentTreeWidget.indexFromItem(selected_item).row()
        lst = self.resultSet[current_tab_index][1:]
        #2.
        cite = lst[row_index]
        return cite
    
    def change_status(self, ind, tab_index, status):
        try:
            tree = None
            for i in self.ui.mainTab.widget(tab_index).children():
                if 'treeWidget' in i.objectName():
                    tree = i
            treeItem = tree.topLevelItem(ind)
            iconval = eval('self.%s_icon' % status)
            treeItem.setIcon(7, iconval)
        except:
            pass

    def removeThread(self, threadnum):
        self.threadpool.pop(threadnum)

    def deleteStoredText(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0: return
        reply = QtGui.QMessageBox.question(self, 'Message',
                                           "The saved text will be deleted. Are you sure?",
                                           QtGui.QMessageBox.Yes,
                                           QtGui.QMessageBox.No)
        if not reply == QtGui.QMessageBox.Yes:
            return
        for i in selected_items:
            selection_row = currentTreeWidget.indexFromItem(i).row()
            # Get the actual record offset by 1
            selection_record = self.resultSet[current_tab_index][selection_row+1]
            eid_of_selection = selection_record['EID']
            try:
                os.remove('%s%s.dxt' % (self.config_dict['storageLocation'], eid_of_selection))
                os.remove('%s%s.txt' % (self.config_dict['storageLocation'], eid_of_selection))
                os.remove('%s%s.pdf' % (self.config_dict['storageLocation'], eid_of_selection))
            except:
                self.ui.statusbar.clearMessage()
                self.ui.statusbar.showMessage('Record for %s not found' % selection_record['Title'], 2000)
            self.change_status(selection_row,current_tab_index, "notDone")

    def tag_selection(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0: return
        text, ok = QtGui.QInputDialog.getText(self, 'Tag Dialog', 'Enter tags for selection:')
        if ok:
            tag_name = str(text)
        else:
            return
        for i in selected_items:
            selection_row = currentTreeWidget.indexFromItem(i).row()
            selection_record = self.resultSet[current_tab_index][selection_row+1]
            eid_of_selection = selection_record['EID']
            tags = selection_record['Tags'].split(',')
            tags = [x.strip() for x in tags]
            if len(tags) == 1:
                if tags[0] == '':
                    tags = []
            tags += [tag_name]
            new_tag_name = ', '.join(tags)
            selection_record['Tags'] =  new_tag_name
            try:
                filename = '%s%s.dxt' % (self.config_dict['storageLocation'], eid_of_selection)
                if os.path.isfile(filename):
                    f = open(filename, 'w')
                    f.write(repr(selection_record)); f.close()
                    treeItem = currentTreeWidget.topLevelItem(selection_row)
                    treeItem.setText(6, new_tag_name)
                else:
                    raise
            except:
                self.ui.statusbar.clearMessage()
                self.ui.statusbar.showMessage('Record for %s not found' % selection_record['Title'], 2000)
        self.refresh_tags()

    def delete_tags(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0: return
        reply = QtGui.QMessageBox.question(self, 'Message',
                                           "All tags in selection will be deleted. Are you sure?",
                                           QtGui.QMessageBox.Yes,
                                           QtGui.QMessageBox.No)
        if not reply == QtGui.QMessageBox.Yes:
            return
        for i in selected_items:
            selection_row = currentTreeWidget.indexFromItem(i).row()
            selection_record = self.resultSet[current_tab_index][selection_row+1]
            eid_of_selection = selection_record['EID']
            selection_record['Tags'] =  ''
            try:
                f = open('%s%s.dxt' % (self.config_dict['storageLocation'], eid_of_selection), 'w'); f.write(repr(selection_record)); f.close()
                treeItem = currentTreeWidget.topLevelItem(selection_row)
                treeItem.setText(6, '')
            except:
                self.ui.statusbar.clearMessage()
                self.ui.statusbar.showMessage('Record for %s not found' % selection_record['Title'], 2000)
        self.refresh_tags()

    def edit_tags(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0: return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'Multiple Selections',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        selected_items = selected_items[0]
        selection_row = currentTreeWidget.indexFromItem(selected_items).row()
        selection_record = self.resultSet[current_tab_index][selection_row+1]
        eid_of_selection = selection_record['EID']
        tags = selection_record['Tags']
        text, ok = QtGui.QInputDialog.getText(self, 'Tag Dialog', 'Saved tags for selection:',
                                              QtGui.QLineEdit.Normal, tags)
        if ok:
            tag_name = str(text)
        else:
            return
        selection_record['Tags'] =  tag_name
        try:
            f = open('%s%s.dxt' % (self.config_dict['storageLocation'], eid_of_selection), 'w'); f.write(repr(selection_record)); f.close()
            treeItem = currentTreeWidget.topLevelItem(selection_row)
            treeItem.setText(6, tag_name)
        except:
            self.ui.statusbar.clearMessage()
            self.ui.statusbar.showMessage('Record for %s not found' % selection_record['Title'], 2000)
        self.refresh_tags()
            
    def get_downloaded_file_info(self):
        t = pdf_downloader.SavedDataThread(self.config_dict)
        self.threadpool[self.threadCount] = t
        self.connect(self.threadpool[self.threadCount],
                     QtCore.SIGNAL('obtained files'), self.update_downloaded_file_info)
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage("Obtaining Previously Saved Records")
        self.threadpool[self.threadCount].start_process(self.threadCount)
        self.threadCount += 1
        for i in range(self.ui.mainTab.count()):
            if self.ui.mainTab.tabText(i) == 'CitationControl-Saved':
                self.ui.mainTab.setCurrentIndex(i)
        

    def update_downloaded_file_info(self, lst_of_files, threadnum):
        treeWidget = None
        for i in range(self.ui.mainTab.count()):
            if self.ui.mainTab.tabText(i) == 'CitationControl-Saved':
                for j in self.ui.mainTab.widget(i).children():
                    if 'treeWidget' in j.objectName():
                        treeWidget = j
                        self.resultSet[i] = lst_of_files
                        self.add_data(lst_of_files, treeWidget, False, threadnum)
                        return 
        treeWidget, tabLoc = self.make_new_tab(lst_of_files[0], "Waiting for file load")
        self.add_data(lst_of_files, treeWidget, tabLoc, threadnum)
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage("Obtained previously saved %s records" % (len(lst_of_files)-1))

    def show_selection_status(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage('Selected %s records' % len(selected_items), 5000)
        if len(selected_items) > 1: return
        if len(selected_items) == 0: return
        if self.note_window.noteTextChanged:
            self.note_window.save_note()
        cite = self.getCurrentCitation()
        print cite
        if not self.record_window.isHidden():
            self.edit_record(self.editRecord)
        self.note_window.update_note_html(cite)
        search_term = str(self.ui.lineEdit.text()).strip()
        if search_term == '': return
        self.fullTextSearch()

    def filter_title(self, text):
        self.text_entered(self.ui.TitleFilter, "Title", text)
    def filter_author(self, text):
        self.text_entered(self.ui.AuthorFilter, "Authors", text)
    def filter_year(self, text):
        self.text_entered(self.ui.YearFilter, "Year", text)
    def filter_journal(self, text):
        self.text_entered(self.ui.JournalFilter, "Journal", text)
    def filter_tag(self, text):
        self.text_entered(self.ui.TagFilter, "Tags", text)
        
    def text_entered(self, widgetName, cite_detail, text):
        '''
        Runs whenever text is entered into one of the filter boxes.
        1. Get the text for the filter
        2. Get the current tree and its location in the tabwidget
        3. In the list from resultSet, check whether this text is present. If not, hide the tree item.
        '''
        #1.
        filter_text = str(widgetName.text())
        #2.
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        #3.
        lst_value = self.resultSet[current_tab_index]
        for num, i in enumerate(lst_value[1:]):
            tree_item = currentTreeWidget.topLevelItem(num)
            if not filter_text.lower() in i[cite_detail].lower():
                currentTreeWidget.setItemHidden(tree_item, True)
            else:
                currentTreeWidget.setItemHidden(tree_item, False)
        
        
    def getLocalPdfFile(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'Multiple Selections',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        selected_item = selected_items[0]
        row_index = currentTreeWidget.indexFromItem(selected_item).row()
        cite = self.resultSet[current_tab_index][1:][row_index]
        eid_val = cite['EID']
        pdf_name = '%s%s.pdf' % (self.config_dict['storageLocation'], eid_val)
        pdf_filename = QtGui.QFileDialog.getOpenFileName(self,
                                                         "Open the pdf file",
                                                         "",
                                                         "*.pdf")
        if pdf_filename == '':
            self.ui.statusbar.showMessage("An input file is needed")
            return
        shutil.copyfile(pdf_filename, pdf_name)
        f = pdf_downloader.convert_pdf_to_text(pdf_name, self.config_dict)
        while f: pass
        f = open('%s%s.dxt' % (self.config_dict['storageLocation'], eid_val), 'w'); f.write(repr(cite)); f.close()
        if not os.path.isfile('%s%s.txt' % (self.config_dict['storageLocation'], eid_val)):
            try:
                textVal = pdf_index.getPDFContent(pdf_name)
                f = open('%s%s.txt' % (self.config_dict['storageLocation'], eid_val), 'w'); f.write(textVal); f.close()
                f = open('%s%s.dxt' % (self.config_dict['storageLocation'], eid_val), 'w'); f.write(repr(cite)); f.close()
            except:
                pass
        x = open('%s%s.txt' % (self.config_dict['storageLocation'], eid_val)).read()
        x = ' '.join(x.split())
        x = x.split('. ')
        x = '\n'.join(x)
        f = open('%s%s.txt' % (self.config_dict['storageLocation'], eid_val), 'w'); f.write(x); f.close()
        f = open('%s%s.dxt' % (self.config_dict['storageLocation'], eid_val), 'w'); f.write(repr(cite)); f.close()
        if not self.config_dict['savePdfsCheck'] == 'Yes':
            os.remove(pdf_name)
        if os.path.isfile('%s%s.txt' % (self.config_dict['storageLocation'], eid_val)):
                selected_item.setIcon(7, self.done_icon)
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage('Records added')

    def downloadPdfFile(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'Multiple Selections',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        selected_item = selected_items[0]
        row_index = currentTreeWidget.indexFromItem(selected_item).row()
        lst = self.resultSet[current_tab_index][1:]
        cite = lst[row_index]
        try:
            detail = eval(open('%s%s.dxt' % (self.config_dict['storageLocation'], cite['EID'])).read())
        except:
            QtGui.QMessageBox.warning (self, 'Record not found.',
                                           'Works only for saved records. \
                                           Record for %s not found' % cite['Title'],
                                       QtGui.QMessageBox.Ok)
            return
        if not 'pdfLocation' in cite:
            t = pdf_downloader.PDFDownloadThread(self.config_dict)
            self.threadpool[self.threadCount] = t
            self.connect(self.threadpool[self.threadCount],
                         QtCore.SIGNAL("pdfLinkObtained"), self.save_pdf)
            self.threadpool[self.threadCount].start_process(row_index,
                                                            current_tab_index,
                                                            lst,
                                                            self.threadCount,
                                                            True)
            self.threadCount += 1
        else:
            self.save_pdf(cite)


    def save_pdf(self, citeItem):
        title = citeItem['Title']
        eid_val = citeItem['EID']
        pdf_link = citeItem['pdfLocation']
        if not pdf_link:
            QtGui.QMessageBox.warning (self, 'No pdf file.',
                                           'Cant get pdf for %s automatically.' % title,
                                       QtGui.QMessageBox.Ok)
            return
        pdf_filename = QtGui.QFileDialog.getSaveFileName(self,
                                                         "Save the pdf file for %s" % title,
                                                         "",
                                                         "*.pdf")
        pdf_filename = str(pdf_filename)
        if pdf_filename == '':
            self.ui.statusbar.showMessage("An input file is needed")
            return
        if not pdf_filename.endswith('.pdf'):
            pdf_filename = pdf_filename + '.pdf'
        self.save_pdf_to_location(pdf_link, pdf_filename, title, citeItem)

    def save_pdf_to_location(self, pdf_link, pdf_filename, title, cite_item):
        try:
            t = pdf_downloader.PDFSaveThread(self.config_dict, pdf_link, pdf_filename, cite_item, title)
            self.threadpool[self.threadCount] = t
            self.connect(self.threadpool[self.threadCount],
                     QtCore.SIGNAL('done'), self.done_saving_pdfs)
            self.connect(self.threadpool[self.threadCount],
                     QtCore.SIGNAL('error'), self.error_saving_pdfs)
            self.threadpool[self.threadCount].start_process()
            self.threadCount += 1
        except:
            QtGui.QMessageBox.warning (self, 'Error Saving.',
                                               'Pdf file for %s not saved' % title,
                                           QtGui.QMessageBox.Ok)
    def done_saving_pdfs(self, title):
        QtGui.QMessageBox.information (self, 'File saved.',
                                               'Pdf file for %s saved' % title,
                                           QtGui.QMessageBox.Ok)
    def error_saving_pdfs(self, title):
        QtGui.QMessageBox.warning (self, 'Error Saving.',
                                               'Pdf file for %s not saved' % title,
                                           QtGui.QMessageBox.Ok)
        
    def treeWidgetSized(self, treeWidget):
        treeWidget.header().resizeSection(0, 300)
        treeWidget.header().setResizeMode(0, QtGui.QHeaderView.Interactive)
        for i in range(1,6):
            treeWidget.header().resizeSection(i, 60)
            treeWidget.header().setResizeMode(i, QtGui.QHeaderView.Interactive)
            
    def test(self):
        reload(pdf_downloader)
        reload(reference_retrieve)

    def aboutCitationControl(self):
        self.reloadAll()
        QtGui.QMessageBox.about(self, "About Citation Control", """
        %s
        (Pubmed)
        Copyright (c) Ajith Warrier
        Released: 01 March 2011.
        """ % __current_version__)

    def open_preferences(self):
        self.window = QtGui.QDialog(self)
        self.pref = Ui_PreferencesDialog()
        self.pref.setupUi(self.window)
        self.pref.proxySitePwd.setEchoMode(2)
        self.pref.tabWidget.setTabText(0, 'Connection settings')
        self.pref.tabWidget.setTabText(1, 'Storage')
        self.pref.tabWidget.setTabText(2, 'PDF options')
        self.bBox_ids = {1 : self.pref.tagFullPath,
                         2 : self.pref.tagDir,
                         3 : self.pref.tagNone,
                         4 : self.pref.tagCustom}
        self.bBox = QtGui.QButtonGroup(self)
        for key in self.bBox_ids:
            self.bBox.addButton(self.bBox_ids[key], key)
        self.connect(self.pref.displCharactersCheckBox, QtCore.SIGNAL('stateChanged (int)'),
                     self.display_characters)
        self.connect(self.pref.radioButtonYesProxy, QtCore.SIGNAL('toggled(bool)'),
                     self.proxy_situation)
        self.connect(self.pref.radioButtonNoProxy, QtCore.SIGNAL('toggled(bool)'),
                     self.non_proxy_situation)
        self.connect(self.pref.buttonBox, QtCore.SIGNAL('accepted()'),
                     self.change_preferences)
        self.connect(self.pref.buttonBox, QtCore.SIGNAL('rejected()'),
                     self.dont_change_preferences)
        self.connect(self.pref.default_reset, QtCore.SIGNAL('clicked()'),
                     self.reset_to_default)
        self.connect(self.pref.browseStorageFolder, QtCore.SIGNAL('clicked()'),
                     self.search_for_storage_folder)
        config_dict = {}
        self.populate_configuration('../CitationControl.conf', config_dict)
        self.enter_preferences(config_dict)
        self.window.show()

    def search_for_storage_folder(self):
        directory = QtGui.QFileDialog.getExistingDirectory(self, 'Select Location for storage.')
        if directory == '':
            QtGui.QMessageBox.warning (self, 'An output folder is needed',
                                           'The temporary output folder will be delete \
                                           when you uninstall this program.',
                                           QtGui.QMessageBox.Ok)
            self.search_for_storage_folder()
        self.pref.storageFolderLocation.setText(str(directory) + os.sep)
        
    
    def display_characters(self, checkState):
        if checkState == 2:
            self.pref.proxySitePwd.setEchoMode(0)
        else:
            self.pref.proxySitePwd.setEchoMode(2)
            
    def proxy_situation(self, toggledSituation):
        self.pref.radioButtonNoProxy.setDown(False)
        self.pref.radioButtonYesProxy.setDown(True)
        self.pref.proxySiteLineEdit.setReadOnly(False)
        self.pref.proxySiteUsername.setReadOnly(False)
        self.pref.proxySitePwd.setReadOnly(False)
        self.pref.proxySiteLineEdit.setStyleSheet("QLineEdit { color: black;}")
        self.pref.proxySiteUsername.setStyleSheet("QLineEdit { color: black;}")
        self.pref.proxySitePwd.setStyleSheet("QLineEdit { color: black;}")
    
    def non_proxy_situation(self, toggledSituation):
        self.pref.radioButtonNoProxy.setDown(True)
        self.pref.radioButtonYesProxy.setDown(False)
        self.pref.proxySiteLineEdit.setReadOnly(True)
        self.pref.proxySiteUsername.setReadOnly(True)
        self.pref.proxySiteLineEdit.setStyleSheet("QLineEdit { color: lightgray;}")
        self.pref.proxySiteUsername.setStyleSheet("QLineEdit { color: lightgray;}")
        self.pref.proxySitePwd.setStyleSheet("QLineEdit { color: lightgray;}")
        self.pref.proxySitePwd.setReadOnly(True)

    def change_preferences(self):
        if self.pref.radioButtonNoProxy.isChecked():
            proxyreqd = 'No'
        elif self.pref.radioButtonNoProxy.isDown():
            proxyreqd = 'No'
        else:
            proxyreqd = 'Yes'
            
        if self.pref.savePdfsCheck.isChecked():
            pdfs_check = 'Yes'
        else:
            pdfs_check = 'No'

        if self.pref.allowDblClckPdfs.isChecked():
            dblClickedAllowed = 'Yes'
        else:
            dblClickedAllowed = 'No'

        if self.pref.markDuplicates.isChecked():
            dup_mark = 'Yes'
        elif self.pref.markDuplicates.isDown():
            dup_mark = 'Yes'
        else:
            dup_mark = 'No'
        checkName = self.bBox.checkedId()
        tag_name = self.bBox_ids[checkName].objectName()
        tag_text = self.pref.tagCustomEdt.text()
        if tag_text == '':
            tag_text = 'None'
        pwd = str(self.pref.proxySitePwd.text())
        username = self.pref.proxySiteUsername.text()
        proxysite = self.pref.proxySiteLineEdit.text()
        storageLocation = self.pref.storageFolderLocation.text()
        output_text = ["# Fill out the following details. Until a dialog is written, this",
                       "# information needs to be entered manually.",
                       "# All lines starting with # will be ignored.",
                       "# This file will be automatically updated during the next run.",
                       "proxyrequired %s" % proxyreqd,
                       "proxysite     %s" % proxysite,
                       "username      %s" % username,
                       " ",
                       "iconLocation	    icons/" ,
                       "# The storage location",
                       " ",                       
                       "storageLocation	%s" % storageLocation,
                       "# Should pdfs be saved",
                       "savePdfsCheck  %s" % pdfs_check,
                       "# Allow double click to open pdfs",
                       "allowDblClckPdfs %s" % dblClickedAllowed,
                       "# Mark duplicates, if this value is set as No, then original records and pdfs will be overwritten with the newest duplicates.",
                       "markDuplicates %s" % dup_mark,
                       "# Decision on tags during indexing of pdfs",
                       "tags_value	%s" % tag_name,
                       "tags_text	%s" % tag_text]
        output_text = '\n'.join(output_text)
        f = open('../CitationControl.conf', 'w'); f.write(output_text); f.close()
        import bz2
        compressVal = '"%s"' % bz2.compress(pwd)
        f = open('adt', 'w'); f.write(compressVal); f.close()
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage('Preferences changed', 2000)
        QtGui.QMessageBox.information (self, 'Restart CitationControl',
                                           'For changes to take effect, restart CitationControl',
                                       QtGui.QMessageBox.Ok)

    def dont_change_preferences(self):
        '''
        If the Preferences dialog is canceled.
        '''
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage('Preferences not changed', 2000)

    def reset_to_default(self):
        '''
        Read the default configuration when the button is pressed.
        '''
        config_dict = {}
        self.populate_configuration('../CitationControl_default.conf', config_dict)
        self.enter_preferences(config_dict)

    def populate_configuration(self, conf_file, output_dict):
        '''
        A utility function to copy the configuration to a file.
        '''
        configText = open(conf_file).readlines()
        try:
            x = open('adt').read()
            x = x[1:-1]
            import bz2
            x = bz2.decompress(x)
            output_dict['password'] = x
        except:
            output_dict['password'] = ''

        configText = [x for x in configText if not x.startswith('#')]
        for i in configText:
            if not i.strip() == '':
                vals = i.split()
                header = vals[0].strip(); value = vals[1].strip()
                output_dict[header] = value
        if sys.platform == "win32":
            output_dict['pdfToTextLocation'] = 'xpdf\pdftotext.exe'
        elif sys.platform == "darwin":
            output_dict['pdfToTextLocation'] = 'pdftotext'
        else:
            output_dict['pdfToTextLocation'] = 'pdftotext'
        storageLoc = output_dict['storageLocation']
        if not os.path.isdir(storageLoc):
            os.mkdir(storageLoc)
                
    def enter_preferences(self, config_dict):
        '''
        A utility function to enter preferences into the preferences dialog.
        '''
        if config_dict['proxyrequired'] == 'No':
            self.non_proxy_situation(True)
        if config_dict['proxyrequired'] == 'Yes':
            self.proxy_situation(True)
        self.pref.proxySiteLineEdit.setText(config_dict['proxysite'])
        if not config_dict['tags_text'] == 'None':
            self.pref.tagCustomEdt.setText(config_dict['tags_text'])
        self.pref.proxySiteUsername.setText(config_dict['username'])
        self.pref.proxySitePwd.setText(config_dict['password'])
        self.pref.storageFolderLocation.setText(config_dict['storageLocation'])
        if config_dict['savePdfsCheck'] == 'Yes':
            self.pref.savePdfsCheck.setChecked(True)
        else:
            self.pref.savePdfsCheck.setChecked(False)

        if config_dict['allowDblClckPdfs'] == 'Yes':
            self.pref.allowDblClckPdfs.setChecked(True)
        else:
            self.pref.allowDblClckPdfs.setChecked(False)

        if config_dict['markDuplicates'] == 'Yes':
            self.pref.markDuplicates.setChecked(True)
        else:
            self.pref.overwrtDuplicates.setChecked(True)

        tag_button = config_dict['tags_value']
        tag_button = eval('self.pref.' + tag_button)
        tag_button.setChecked(True)
        

    def index_local_pdfs(self):
        self.search_widg = None
        self.extracted_pdf_list = []
        self.window2 = pdf_index.IndexWindow(self)
        self.connect(self.window2, QtCore.SIGNAL('windowClosed'), self.index_window_closed)
        self.indexD = Ui_IndexingDialog()
        self.indexD.setupUi(self.window2)
        self.connect(self.indexD.entire_computer_button, QtCore.SIGNAL('clicked()'),
                     self.index_all_pdfs)
        self.connect(self.indexD.folder_choice_button, QtCore.SIGNAL('clicked()'),
                     self.index_folder_pdfs)
        self.connect(self.indexD.buttonBox, QtCore.SIGNAL('accepted()'),
                     self.index_window_closed)
        self.connect(self.indexD.buttonBox, QtCore.SIGNAL('rejected()'),
                     self.index_window_closed)
        self.window2.show()

    def index_window_closed(self):
        if self.search_widg:
            self.search_widg.running = False
        self.get_downloaded_file_info()
    
    def index_all_pdfs(self):
        if self.search_widg:
            self.search_widg.running = False
        reply = QtGui.QMessageBox.question(self, 'Entire Computer?',
                                           """This can take a long time!\nEvery pdf in your computer will be tested.\nThis includes non article pdfs as well.\nIf you have a lot of pdfs, this might take the time equivalent of defragmenting your computer.\nYou can, however, quit at any time.\n\n Are you sure you want to continue?""",
                                           QtGui.QMessageBox.Yes,
                                           QtGui.QMessageBox.No)
        if not reply == QtGui.QMessageBox.Yes:
            return
        directory = common_tools.get_root_folder()
        self.run_indexing(directory)

    def index_folder_pdfs(self):
        if self.search_widg:
            self.search_widg.running = False
        directory = QtGui.QFileDialog.getExistingDirectory(self, 'Select folder with stored pdfs.')
        if directory == '':
            return
        self.run_indexing(str(directory))
        
    def run_indexing(self, directory):
        import datetime
        timeN = datetime.datetime.now()      
        self.search_widg = pdf_index.PDFIndexingThread(str(directory), self.config_dict, timeN)
        self.connect(self.search_widg, QtCore.SIGNAL('pdf_file'),
                     self.updateExtracted)
        self.connect(self.search_widg, QtCore.SIGNAL('no_pdf_file'),
                     self.updateError)
        self.connect(self.search_widg, QtCore.SIGNAL('dup_pdf_file'),
                     self.updateDuplicates)
        self.search_widg.start_process()
        
    def updateExtracted(self, appendVal):
        '''
        When a pdf can be converted,
        then insert into the right box.
        '''        
        update_val = appendVal
        self.indexD.extractedPdfs.moveCursor(QtGui.QTextCursor.End, 1)
        self.indexD.extractedPdfs.insertHtml(update_val)

    def updateError(self, appendVal): 
        '''
        When a pdf cannot be converted,
        then insert into the error box.
        '''
        update_val = appendVal
        self.indexD.errorPdfs.moveCursor(QtGui.QTextCursor.End, 1)        
        self.indexD.errorPdfs.insertHtml(update_val)

    def updateDuplicates(self, appendVal):
        '''
        When a pdf cannot be converted,
        then insert into the error box.
        '''
        update_val = appendVal
        self.indexD.duplicatePdfs.moveCursor(QtGui.QTextCursor.End, 1)        
        self.indexD.duplicatePdfs.insertHtml(update_val)

    def item_double_clicked(self, item):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'Multiple Selections',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        selected_item = selected_items[0]
        row_index = currentTreeWidget.indexFromItem(selected_item).row()
        lst = self.resultSet[current_tab_index][1:]
        
        cite = lst[row_index]
        try:
            pdf_name = '%s%s.pdf' % (self.config_dict['storageLocation'], cite['EID'])
            if not os.path.isfile(pdf_name): raise
            if sys.platform == "win32":
                osFunc = 'start'
            elif sys.platform == "darwin":
                osFunc = 'open'
            else:
                osFunc = 'xdg-open'
            osFunc = '%s %s &' % (osFunc, pdf_name)
            os.popen(osFunc)
        except:
            QtGui.QMessageBox.warning (self, 'Record not found.',
                                           'Works only for saved records. Record for "%s" not found. Try obtaining this pdf again.' % cite['Title'],
                                       QtGui.QMessageBox.Ok)
            return

    def on_start_freeze(self):
        if self.prog_window.isHidden():
            self.prog_window.show()

    def on_end_freeze(self):
        if not self.prog_window.isHidden():
            self.prog_window.hide()

    def extract_images(self):
        '''
        Main function to extract images from the pdf file.close
        1. Make sure that previous picture viewers are deleted and get the selected items.
        2. Get the specific file and create a temporary dir to save the images.
        3. Copy the pdf file to this dir and extract images. Then remove pdf files.
        4. Show images.
        5. If there is an error, remove the pdf file and show a message.
        '''
        #1.
        self.pv = None
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        if len(selected_items) == 0:
            QtGui.QMessageBox.information (self, 'No Selection',
                                           'A record needs to be selected', QtGui.QMessageBox.Ok)
            return
        if len(selected_items) > 1:
            QtGui.QMessageBox.information (self, 'Multiple Selections',
                                           'Only one record can be selected for this process',
                                           QtGui.QMessageBox.Ok)
            return
        selected_item = selected_items[0]
        row_index = currentTreeWidget.indexFromItem(selected_item).row()
        lst = self.resultSet[current_tab_index][1:]
        #2.
        cite = lst[row_index]
        tempdir = self.config_dict['storageLocation'] + 'temp/'
        if not os.path.isdir(tempdir):
            os.mkdir(tempdir)
        pdf_name = '%s%s.pdf' % (self.config_dict['storageLocation'], cite['EID'])
        new_pdf_name = '%s%s.pdf' % (tempdir, cite['EID'])
        #3.
        if os.path.isfile(pdf_name):
            shutil.copyfile(pdf_name, new_pdf_name)
        else:
            QtGui.QMessageBox.information (self, 'Pdf file not found',
                                           'Check "save pdfs" in preferences if you need this function. Then reload the searchable text for this file.',
                                           QtGui.QMessageBox.Ok)
            return
        if sys.platform == "win32":
            osFunc = 'xpdf\pdfimages.exe'
        else:
            osFunc = 'pdfimages'
        
        osFunc = "%s -j %s %sFigure" % (osFunc, new_pdf_name, tempdir)
        try:           
            f = os.system(osFunc)
            while f: pass
            os.remove(new_pdf_name)
            #4.
            self.pv = picture_viewer.PictureViewer(tempdir, self)           
            self.pv.showMaximized()
            self.img_window.hide()
        except:
            if os.path.isfile(pdf_name):
                os.remove(new_pdf_name)
            QtGui.QMessageBox.information (self, 'Images could not be extracted',
                                           'One possible reason is that the pdf file is locked.',
                                           QtGui.QMessageBox.Ok)
        self.pv = None
        f = None

    def closeEvent(self, event):
        self.threadCount = 0
        self.threadpool = {}
        self.pdf_download_pool = []
        self.current_pdf_threads = []
        self.done_threads = 0
        self.started_threads = 0
        self.threads_done = True
        
    def reloadAll(self):
        reload(pdf_index)
        reload(pdf_downloader)
        reload(reference_retrieve)
        reload(picture_viewer)
        reload(notes_editor_wrapper)
        reload(record_adder_wrapper)
        self.initialize_notes_window()

    def tabSelectionChanged(self, itemNum):
        if self.ui.mainTab.tabText(itemNum) == 'CitationControl-Saved':
            self.get_downloaded_file_info()
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        for i in range(currentTreeWidget.topLevelItemCount()):
            item = currentTreeWidget.topLevelItem(i)
            item.setHidden(False)
        


    def webCitationControl(self, page):
        import help_browser
        import urllib
        filename = urllib.pathname2url('./help/%s.html' % page)
        self.help_window = QtGui.QDialog(self)
        self.help_dialog = help_browser.Ui_Dialog()
        self.help_dialog.setupUi(self.help_window)
        self.help_dialog.webView.setUrl(QtCore.QUrl(filename))
        self.help_window.show()

        
    def webCitationControl0(self): self.webCitationControl('change_prefs')
    def webCitationControl1(self): self.webCitationControl('access_db')
    def webCitationControl2(self): self.webCitationControl('index_articles')
    def webCitationControl3(self): self.webCitationControl('search_online')
    def webCitationControl4(self): self.webCitationControl('get_citerefs')
    def webCitationControl5(self): self.webCitationControl('save_reload')
    def webCitationControl6(self): self.webCitationControl('bib_export')
    def webCitationControl7(self): self.webCitationControl('edit_record')
    def webCitationControl8(self): self.webCitationControl('open_pdfs')
    def webCitationControl9(self): self.webCitationControl('view_images')
    def webCitationControl10(self): self.webCitationControl('obtain_pdfs')
    def webCitationControl11(self): self.webCitationControl('search_keywords')
    def webCitationControl12(self): self.webCitationControl('filter_articles')
    def webCitationControl13(self): self.webCitationControl('save_note')
    def webCitationControl14(self): self.webCitationControl('use_operators')
    def webCitationControl15(self): self.webCitationControl('tag_articles')
    def webCitationControl16(self): self.webCitationControl('use_clipboard')
    def webCitationControl17(self): self.webCitationControl('local_pdf_add')
    def webCitationControl18(self): self.webCitationControl('delete_saved_data')


    def populate_help_menu(self):
        self.helpActions = []
        self.help_dict = [
            [['change_prefs'], ['change my preferences?']],
            [['access_db'], ['access my database?']],
            [['index_articles'], ['index pdfs in my computer?']],
            [['search_online'], ['do an online search for articles?']],
            [['get_citerefs'], ['get citations and references?']],
            [['save_reload'], ['save and reload my searched session?']],
            [['bib_export'], ['export my bibliography?']],
            [['edit_record'], ['edit records or add new ones?']],
            [['open_pdfs'], ['open pdfs in my database?']],
            [['view_images'], ['view images from selected files?']],
            [['obtain_pdfs'], ['download multiple pdfs of articles?']],
            [['search_keywords'], ['search the full text of articles?']],
            [['filter_articles'], ['show articles that contain specific keywords?']],
            [['save_note'], ['take notes for an article?']],
            [['use_operators'], ['use operators during searches?']],
            [['tag_articles'], ['tag and organize articles?']],
            [['use_clipboard'], ['use the clipboard function?']],
            [['local_pdf_add'], ['add local pdfs if they are not found?']],
            [['delete_saved_data'], ['delete articles from my database?']]
            ]
        for j,i in enumerate(self.help_dict):
            action_val = QtGui.QAction(QtGui.QIcon('%shelp2.png' % self.config_dict['iconLocation']),
                                                    i[1][0], self)
            self.helpActions.append(action_val)
            self.connect(self.helpActions[len(self.helpActions)-1],
                         QtCore.SIGNAL('triggered()'), eval('self.webCitationControl'+str(j)))
            self.helpMenu.addAction(self.helpActions[len(self.helpActions)-1])
            

    def add_notes(self):
        '''
        Added in 1.05 if notes need to be added to a record.
        '''
        if self.note_window.isHidden():
            self.note_window.show()


    def initialize_notes_window(self):
        self.note_window = notes_editor_wrapper.NoteWindow(self)
        self.note_window.initialize(self.config_dict)
        self.note_window.hide()
        
    def add_strings_to_clipboard(self):
        self.add_to_clipboard()
        selected_text = self.ui.textEdit.textCursor().selectedText()
        selected_text = pdf_index.remove_title_special_chars(unicode(selected_text))
        selected_text = [selected_text]
        self.clipboard += selected_text

    def show_downloaded_only(self):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        for i in range(currentTreeWidget.topLevelItemCount()):
            item = currentTreeWidget.topLevelItem(i)
            item_serial = item.icon(7).serialNumber()
            if item_serial == 4:
                item.setHidden(False)
            elif item_serial == 7:
                item.setHidden(False)
            else:
                item.setHidden(True)

    def move_to_tab(self, event):
        tabIndex = self.openWindows.index(event)
        self.ui.mainTab.setCurrentIndex(tabIndex)

    def save_current_session(self):
        '''
        Saving current session.
        '''
        saved_resultSet = self.resultSet[:]
        for j,i in  enumerate(saved_resultSet):
            if i[0] == "CitationControl-Saved":
                saved_resultSet.pop(j)
        if len(saved_resultSet) == 0:
            QtGui.QMessageBox.warning (self, 'No tabs to be saved',
                                           'Tabs other than the database are needed for saving.\nThe database "CitationControl-Saved" is always saved automatically.',
                                           QtGui.QMessageBox.Ok)
            return
        if not self.currentSession:
            sess_filename = QtGui.QFileDialog.getSaveFileName(self,
                                                         "Save this session",
                                                         "",
                                                         "*.sess")
            if not sess_filename: print 'No file chosen'; return
            self.currentSession = sess_filename
        else:
            sess_filename = self.currentSession
        sess_filename = str(sess_filename)
        if not sess_filename.endswith('.sess'):
            sess_filename += '.sess'
        f = open(sess_filename, 'w')
        f.write(repr(saved_resultSet)); f.close()
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage("Session saved at %s" % sess_filename, 3000)
        
    def open_saved_session(self):
        save_check = self.check_if_session_needs_saving()
        if not save_check:
            sess_filename = QtGui.QFileDialog.getOpenFileName(self,
                                                              "Open previously saved session",
                                                              "",
                                                              "*.sess")
            if not sess_filename: print 'No file chosen'; return
            self.currentSession = sess_filename
            sess_filename = str(sess_filename)
            session_details = eval(open(sess_filename).read())
            self.close_current_session()
            for i in session_details:
                treeWidget, tabLoc = self.make_new_tab(i[0], "Waiting for file load")
                self.add_data(i, treeWidget, tabLoc, 0)
        
    def close_current_session(self):
        total_current_tabs = range(self.ui.mainTab.count())
        total_current_tabs.reverse()
        for i in total_current_tabs:
            if self.ui.mainTab.tabText(i) == 'CitationControl-Saved':
                pass
            else:
                self.tabClosed(i)

    def check_if_session_needs_saving(self):
        x = QtGui.QMessageBox.information (self, 'Session saving',
                                           "Changes in this session will be lost. \nIf you have already saved it or don't wish to, just hit 'Cancel'.\n\nDo you want to save this session?",
                                           QtGui.QMessageBox.Ok, QtGui.QMessageBox.Cancel)
        if x == QtGui.QMessageBox.Ok:
            self.save_current_session()
            return False
        else:
            return False

    def close_windows(self):
        save_check = self.check_if_session_needs_saving()
        if not save_check:
            self.close()

    def edit_record(self, event):
        if self.record_window.isHidden():
            self.record_window.show()
        if event == self.addRecord:
            eid, eid_file = self.get_new_eid()
            self.record_window.set_save_filename(eid, eid_file, self.config_dict)
            self.record_window.clear_fields()
        else:
            cite = self.getCurrentCitation()
            self.record_window.set_save_filename(cite['EID'],
                                                 '%s%s.dxt' % (self.config_dict['storageLocation'],
                                                               cite['EID']),
                                                 self.config_dict)
            self.record_window.update_info()

    def get_new_eid(self):
        '''
        New eid which is just a random five digit number which is not a stored file name.
        '''

        from random import randint
        new_record_eid = randint(10000, 99999)
        try:
            new_filename = '%s%s.dxt' % (self.config_dict['storageLocation'], new_record_eid)
            open(new_filename)
            self.get_new_eid()
        except:
            return new_record_eid, new_filename

    def update_done(self, eid_val):
        self.get_downloaded_file_info()

    def select_item_by_eid(self, eid):
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        lst = self.resultSet[current_tab_index][1:]
        item = None
        for j,i in enumerate(lst):
            if i['EID'] == eid:
                item = currentTreeWidget.topLevelItem(j)
        currentTreeWidget.setCurrentItem(item)

    def export_bibliography(self):
        choice = QtGui.QMessageBox.information (self, 'Experimental export.',
                                                'Exporting to a .bib file is experimental. \
                                                \n\nSome problems you might encounter are: \
                                                \n * Unpublished articles need to be fixed by editing. \
                                                \n * Special characters in fields. \
                                                \n * Issue number is missing. This might happen for some \
                                                \n   records. \
                                                \n All the above issues can be fixed by editing the records. \
                                                \n\n The .bib file is solely for export. The Notes file \
                                                you have created will not be transferred.',
                                                QtGui.QMessageBox.Ok, QtGui.QMessageBox.Cancel)
        if choice == QtGui.QMessageBox.Cancel: return
        currentTreeWidget, current_tab_index = self.getTreeWidget_index()
        selected_items = currentTreeWidget.selectedItems()
        
        if len(selected_items) == 0: return
        output_list = []
        for i in selected_items:
            selection_row = currentTreeWidget.indexFromItem(i).row()
            selection_record = self.resultSet[current_tab_index][selection_row+1]
            number = re.findall('\((.*?)\)', selection_record['Issue'])
            title = selection_record['Title']
            author = selection_record['Authors']
            author = author.replace('.,', '. and')
            year = selection_record['Year']
            journal = selection_record['Journal']
            url = selection_record['ArticleLink']
            pages = selection_record['Pages']
            pages = pages.replace('.', '')
            pages = pages.replace('pp', '')
            pages = pages.strip()
            bibKeyVal = ''
            bibKeyVal = author.split(',')
            bibKeyVal = bibKeyVal[0].strip() + year
            bibKeyVal = bibKeyVal.strip()
            if len(number) == 0:
                number = ''
                volume = selection_record['Issue'].strip()
            else:
                number = number[0]
                volume = selection_record['Issue'][:selection_record['Issue'].find('(')]
            
            text = """@article{%s,
            author = {%s},
            title = {%s},
            journal = {%s},
            year = {%s},
            volume = {%s},
            number = {%s},
            pages = {%s},
            url = {%s}
            }""" % (bibKeyVal, author, title, journal, year, volume, number, pages, url)
            output_list.append(text)
        output_string = '\n'.join(output_list)
        bib_filename = QtGui.QFileDialog.getSaveFileName(self,
                                                         "Save or append the bib file.",
                                                         "",
                                                         "*.bib")
        bib_filename = str(bib_filename)
        if bib_filename == '':
            self.ui.statusbar.showMessage("An input file is needed")
            return
        if not bib_filename.endswith('.bib'):
            bib_filename = bib_filename + '.bib'
        f = open(bib_filename, 'a')
        f.write(output_string); f.close()
        self.ui.statusbar.clearMessage()
        self.ui.statusbar.showMessage("Bibliography saved at %s" % bib_filename, 3000)

    def refresh_tags(self):
        db_index = 'test'
        for i in range(self.ui.mainTab.count()):
            if self.ui.mainTab.tabText(i) == 'CitationControl-Saved':
                db_index = i
        if db_index == 'test': return
        tags_vals = [i['Tags'] for i in self.resultSet[db_index][1:]]
        all_tags = ['Show all']
        new_tags = []
        for tags in tags_vals:
            tags = tags.split(',')
            tags = [x.strip() for x in tags]
            for tag in tags:
                if not tag in new_tags:
                    new_tags.append(tag)
        new_tags.sort()
        all_tags += new_tags
        f = open("%stags.tgt" % self.config_dict['storageLocation'], 'w'); f.write(repr(all_tags)); f.close()
        self.read_tags()
        
    def read_tags(self):
        try:
            self.all_tags = open("%stags.tgt" % self.config_dict['storageLocation']).read()
            self.all_tags = eval(self.all_tags)
            self.ui.tagManagerTreeWidget.clear()
            for tag in self.all_tags:
                a = QtGui.QTreeWidgetItem(self.ui.tagManagerTreeWidget)
                a.setText(0, tag)
        except:
            pass
        
    def tag_selected(self):
        selected_items = self.ui.tagManagerTreeWidget.selectedItems()
        self.ui.statusbar.clearMessage()
        if len(selected_items) == 0: return
        selected_item = selected_items[0]
        tag_text = str(selected_item.text(0))
        for i in range(self.ui.mainTab.count()):
            if self.ui.mainTab.tabText(i) == 'CitationControl-Saved':
                self.ui.mainTab.setCurrentIndex(i)
                tags_vals = [x['Tags'] for x in self.resultSet[i][1:]]
                for j in self.ui.mainTab.widget(i).children():
                    if 'treeWidget' in j.objectName():
                        treeWidget = j
        for i in range(treeWidget.topLevelItemCount()):
            item = treeWidget.topLevelItem(i)
            item.setSelected(False)
            if tag_text == 'Show all':
                item.setHidden(False)
                continue
            tags = tags_vals[i].split(',')
            tags = [x.strip() for x in tags]
            if not tag_text in tags:
                item.setHidden(True)
            else:
                item.setHidden(False)
        
    def remove_tags(self):
        selected_items = self.ui.tagManagerTreeWidget.selectedItems()
        self.ui.statusbar.clearMessage()
        if len(selected_items) == 0: return
        selected_item = selected_items[0]
        tag_text = str(selected_item.text(0))
        if tag_text == 'Show all': return
        for i in range(self.ui.mainTab.count()):
            if self.ui.mainTab.tabText(i) == 'CitationControl-Saved':
                self.ui.mainTab.setCurrentIndex(i)
                current_tab_index = i
                tags_vals = [x['Tags'] for x in self.resultSet[i][1:]]
                for j in self.ui.mainTab.widget(i).children():
                    if 'treeWidget' in j.objectName():
                        treeWidget = j
        for i in range(treeWidget.topLevelItemCount()):
            item = treeWidget.topLevelItem(i)
            item.setSelected(False)
            if not item.isHidden():
                tags = tags_vals[i].split(',')
                tags = [x.strip() for x in tags]
                if tag_text in tags:
                    tags.remove(tag_text)
                    selection_record = self.resultSet[current_tab_index][i+1]
                    eid_of_selection = selection_record['EID']
                    if len(tags) == 0:
                        selection_record['Tags'] = ''
                    else:
                        selection_record['Tags'] = ', '.join(tags)
                    try:
                        f = open('%s%s.dxt' % (self.config_dict['storageLocation'], eid_of_selection), 'w')
                        f.write(repr(selection_record)); f.close()
                        item.setText(6, selection_record['Tags'])
                    except:
                        self.ui.statusbar.clearMessage()
                        self.ui.statusbar.showMessage(
                            'Record for %s not found' % selection_record['Title'],
                            2000)
        self.refresh_tags()

    def rename_tags(self):
        selected_items = self.ui.tagManagerTreeWidget.selectedItems()
        self.ui.statusbar.clearMessage()
        if len(selected_items) == 0: return
        selected_item = selected_items[0]
        tag_text = str(selected_item.text(0))
        if tag_text == 'Show all': return
        text, ok = QtGui.QInputDialog.getText(self, 'Rename tags', 'Enter replacement for %s:' % tag_text)
        if ok:
            new_tag_text = str(text)
        else:
            return
        for i in range(self.ui.mainTab.count()):
            if self.ui.mainTab.tabText(i) == 'CitationControl-Saved':
                self.ui.mainTab.setCurrentIndex(i)
                current_tab_index = i
                tags_vals = [x['Tags'] for x in self.resultSet[i][1:]]
                for j in self.ui.mainTab.widget(i).children():
                    if 'treeWidget' in j.objectName():
                        treeWidget = j
        for i in range(treeWidget.topLevelItemCount()):
            item = treeWidget.topLevelItem(i)
            item.setSelected(False)
            if not item.isHidden():
                tags = tags_vals[i].split(',')
                tags = [x.strip() for x in tags]
                if tag_text in tags:
                    tag_index = tags.index(tag_text)
                    tags[tag_index] = new_tag_text
                    selection_record = self.resultSet[current_tab_index][i+1]
                    eid_of_selection = selection_record['EID']
                    if len(tags) == 0:
                        selection_record['Tags'] = ''
                    else:
                        selection_record['Tags'] = ', '.join(tags)
                    try:
                        f = open('%s%s.dxt' % (self.config_dict['storageLocation'], eid_of_selection), 'w')
                        f.write(repr(selection_record)); f.close()
                        item.setText(6, selection_record['Tags'])
                    except:
                        self.ui.statusbar.clearMessage()
                        self.ui.statusbar.showMessage(
                            'Record for %s not found' % selection_record['Title'],
                            2000)
        self.refresh_tags()
        
    def create_tag_manager_context_actions(self):
        self.refreshTMAction = self.create_action('Refresh tags')
        self.removeTMAction = self.create_action('Remove tags')
        self.renameTMAction = self.create_action('Rename tags')
        self.ui.tagManagerTreeWidget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        self.ui.tagManagerTreeWidget.addActions([self.refreshTMAction,
                               self.menuSeparator4,
                               self.removeTMAction, self.renameTMAction])
        self.connect(self.ui.tagManagerTreeWidget,
                     QtCore.SIGNAL('itemSelectionChanged()'), self.tag_selected)

    def create_action(self, title):
        action = QtGui.QAction(
            QtGui.QIcon('%stag.png' % self.config_dict['iconLocation']),
            title, self)
        title_val = [i.lower() for i in title.split()]
        action_name = '_'.join(title_val)
        eval("self.connect(action,QtCore.SIGNAL('triggered()'), self.%s)" % action_name)
        return action
    
    def show_tag_manager(self):
        if not self.ui.tagManagerWidget.isHidden():
            self.ui.tagManagerWidget.hide()
            self.tagManagerAction.setChecked(False)
        else:
            self.ui.tagManagerWidget.show()
            self.tagManagerAction.setChecked(True)

    def create_action_and_connect(self, **kwargs):
        '''Creates a QAction and connects function. Returns the QAction'''
        action = QtGui.QAction(
            QtGui.QIcon(kwargs['icon_file'] % self.config_dict['iconLocation']),
            kwargs['action_label'], self)
        self.connect(action, QtCore.SIGNAL('triggered()'),
                     kwargs['action_function'])
        if kwargs['action_shortcut']:
            action.setShortcut(QtGui.QKeySequence(kwargs['action_shortcut']))
        return action

    def make_connections(self):
        '''
        Delegating make connections to improve readability.
        '''
        # tree widget specific
        self.connect(self.ui.mainTab, QtCore.SIGNAL('tabCloseRequested (int)'),
                     self.tabClosed)
        self.ui.mainTab.currentChanged.connect(self.tabSelectionChanged)
        # Actions
        # File menu   
        self.openRecordsAction = self.create_action_and_connect(
            icon_file='%sfile.png', action_label='&Open saved records', action_function=self.get_downloaded_file_info,
            action_shortcut="Ctrl+f")
        self.ui.menuFile.addAction(self.openRecordsAction)
        self.ui.menuFile.addSeparator()
        self.openSessionAction = QtGui.QAction(
            QtGui.QIcon('%sfile.png' % self.config_dict['iconLocation']),
            'Open sa&ved session', self)
        self.connect(self.openSessionAction, QtCore.SIGNAL('triggered()'),
                     self.open_saved_session)
        self.openSessionAction.setShortcut(QtGui.QKeySequence("Ctrl+o"))        
        self.ui.menuFile.addAction(self.openSessionAction)

        self.savesessionAction = QtGui.QAction(
            QtGui.QIcon('%sfile.png' % self.config_dict['iconLocation']),
            '&Save current session', self)
        self.connect(self.savesessionAction, QtCore.SIGNAL('triggered()'),
                     self.save_current_session)
        self.savesessionAction.setShortcut(QtGui.QKeySequence("Ctrl+s"))                
        self.ui.menuFile.addAction(self.savesessionAction)
        self.ui.menuFile.addSeparator()
        self.indexRecordsAction = QtGui.QAction(
            QtGui.QIcon('%sindex.png' % self.config_dict['iconLocation']),
            '&Index local pdfs', self)
        self.connect(self.indexRecordsAction, QtCore.SIGNAL('triggered()'),
                     self.index_local_pdfs)
        self.ui.menuFile.addAction(self.indexRecordsAction)

        self.exportBibAction = QtGui.QAction(
            QtGui.QIcon('%sfile.png' % self.config_dict['iconLocation']),
            '&Export to a .bib file', self)
        self.connect(self.exportBibAction, QtCore.SIGNAL('triggered()'),
                     self.export_bibliography)
        self.exportBibAction.setShortcut(QtGui.QKeySequence("Ctrl+e"))
        self.ui.menuFile.addAction(self.exportBibAction)
        self.ui.menuFile.addSeparator()
        
        self.exitAction = QtGui.QAction(QtGui.QIcon('%sexit.png' % self.config_dict['iconLocation']),
                                                    '&Quit', self)
        self.connect(self.exitAction, QtCore.SIGNAL('triggered()'),
                     self.close_windows)
        self.ui.menuFile.addAction(self.exitAction)
        #View menu
        self.menuWindows = QtGui.QMenu(self.ui.menubar)
        self.ui.menubar.addAction(self.menuWindows.menuAction())
        self.menuWindows.setTitle(QtGui.QApplication.translate("ScopusRetrMainWindow", "&View", None, QtGui.QApplication.UnicodeUTF8))
        #View menu go to
        self.goToMenu = QtGui.QMenu("Go to ...")
        self.goToMenu.setIcon(self.help_icon)
        self.menuWindows.addMenu(self.goToMenu)
        self.connect(self.goToMenu, QtCore.SIGNAL('triggered(QAction *)'),
                     self.move_to_tab)
        #Other Menus
        self.menuPdf = QtGui.QMenu(self.ui.menubar)
        self.ui.menubar.addAction(self.menuPdf.menuAction())
        self.menuPdf.setTitle(QtGui.QApplication.translate("ScopusRetrMainWindow", "&Pdf", None, QtGui.QApplication.UnicodeUTF8))
        self.menuTag = QtGui.QMenu(self.ui.menubar)
        self.ui.menubar.addAction(self.menuTag.menuAction())
        self.menuTag.setTitle(QtGui.QApplication.translate("ScopusRetrMainWindow", "&Tag", None, QtGui.QApplication.UnicodeUTF8))
        self.menuClip = QtGui.QMenu(self.ui.menubar)
        self.ui.menubar.addAction(self.menuClip.menuAction())
        self.menuClip.setTitle(QtGui.QApplication.translate("ScopusRetrMainWindow", "&Clip", None, QtGui.QApplication.UnicodeUTF8))
        

        self.ui.menubar.removeAction(self.ui.menuHelp.menuAction())
        self.ui.menuHelp = QtGui.QMenu(self.ui.menubar)
        self.ui.menubar.addAction(self.ui.menuHelp.menuAction())
        self.ui.menuHelp.setTitle(QtGui.QApplication.translate("ScopusRetrMainWindow", "&Help", None, QtGui.QApplication.UnicodeUTF8))
        self.menuSeparator2 = QtGui.QAction(None)
        self.menuSeparator2.setSeparator(True)
        self.menuSeparator1 = QtGui.QAction(None)
        self.menuSeparator1.setSeparator(True)
        self.menuSeparator3 = QtGui.QAction(None)
        self.menuSeparator3.setSeparator(True)
        self.menuSeparator4 = QtGui.QAction(None)
        self.menuSeparator4.setSeparator(True)
        #tag menu
        self.tagManagerAction = QtGui.QAction(
            QtGui.QIcon('%stag.png' % self.config_dict['iconLocation']),
            'Tag &Manager', self)
        self.tagManagerAction.setCheckable(True)
        self.connect(self.tagManagerAction,
                     QtCore.SIGNAL('triggered()'), self.show_tag_manager)
        self.menuTag.addAction(self.tagManagerAction)
        self.menuTag.addSeparator()
        self.tagAction = QtGui.QAction(
            QtGui.QIcon('%stag.png' % self.config_dict['iconLocation']),
            '&Tag Selection(s)', self)
        self.connect(self.tagAction,
                     QtCore.SIGNAL('triggered()'), self.tag_selection)
        self.menuTag.addAction(self.tagAction)
        self.removeTagAction = QtGui.QAction(
            QtGui.QIcon('%stag.png' % self.config_dict['iconLocation']),
            '&Remove Tag(s)', self)
        self.connect(self.removeTagAction,
                     QtCore.SIGNAL('triggered()'), self.delete_tags)
        self.menuTag.addAction(self.removeTagAction)
        self.editTagAction = QtGui.QAction(
            QtGui.QIcon('%stag.png' % self.config_dict['iconLocation']),
            '&Edit Tag(s)', self)
        self.connect(self.editTagAction,
                     QtCore.SIGNAL('triggered()'), self.edit_tags)
        self.menuTag.addAction(self.editTagAction)
        
        # Adding text from the view to the clipboard
        self.addStringsToClipboard = QtGui.QAction(
            QtGui.QIcon('%sadd_strings_to_clipboard.png' % self.config_dict['iconLocation']),
            'Add te&xt to session clipboard', self)
        self.connect(self.addStringsToClipboard,
                     QtCore.SIGNAL('triggered()'), self.add_strings_to_clipboard)
        self.addToClipboard = QtGui.QAction(
            QtGui.QIcon('%sadd_to_clipboard.png' % self.config_dict['iconLocation']),
            '&Add to session clipboard', self)
        self.showClipboard = QtGui.QAction(QtGui.QIcon('%sshow_clipboard.png' % self.config_dict['iconLocation']),
                                          '&Show clipboard', self)
        self.clearClipboard = QtGui.QAction(QtGui.QIcon('%sclear_clipboard.png' % self.config_dict['iconLocation']),
                                          '&Clear clipboard', self)
        self.addNotes = QtGui.QAction(
            QtGui.QIcon('%snotes.png' % self.config_dict['iconLocation']),
            '&Notes for this record', self)
        self.recordGroup = QtGui.QActionGroup(self)
        self.editRecord = QtGui.QAction(
            QtGui.QIcon('%snotes.png' % self.config_dict['iconLocation']),
            '&Edit this record', self)
        self.addRecord = QtGui.QAction(
            QtGui.QIcon('%snotes.png' % self.config_dict['iconLocation']),
            '&Add a new record', self)
        self.recordGroup.addAction(self.addRecord)
        self.recordGroup.addAction(self.editRecord)
        self.connect(self.addToClipboard,
                     QtCore.SIGNAL('triggered()'), self.add_to_clipboard)
        self.connect(self.showClipboard,
                     QtCore.SIGNAL('triggered()'), self.show_clipboard)
        self.connect(self.clearClipboard,
                     QtCore.SIGNAL('triggered()'), self.clear_clipboard)
        self.connect(self.addNotes,
                     QtCore.SIGNAL('triggered()'), self.add_notes)
        self.connect(self.recordGroup,
                     QtCore.SIGNAL('triggered(QAction *)'), self.edit_record)
        self.menuClip.addAction(self.addToClipboard)
        self.menuClip.addAction(self.addStringsToClipboard)
        self.ui.menuEdit.addAction(self.addNotes)
        self.ui.menuEdit.addAction(self.editRecord)
        self.ui.menuEdit.addAction(self.addRecord)
        self.menuClip.addAction(self.showClipboard)
        self.menuClip.addAction(self.clearClipboard)
        #pdf menu
        self.getPdfAction = QtGui.QAction(QtGui.QIcon('%spdf.png' % self.config_dict['iconLocation']),
                                          'Add a local &pdf file', self)
        self.connect(self.getPdfAction,
                     QtCore.SIGNAL('triggered()'), self.getLocalPdfFile)
        self.menuPdf.addAction(self.getPdfAction)
        self.downloadPdfAction = QtGui.QAction(QtGui.QIcon('%spdfd.png' % self.config_dict['iconLocation']),
                                          '&Get pdf file from the web', self)
        self.connect(self.downloadPdfAction,
                     QtCore.SIGNAL('triggered()'), self.downloadPdfFile)
        self.menuPdf.addAction(self.downloadPdfAction)
        self.showPdfImagesAction = QtGui.QAction(QtGui.QIcon('%spdf.png' % self.config_dict['iconLocation']),
                                          'Show &images in the pdf file', self)
        self.connect(self.showPdfImagesAction,
                     QtCore.SIGNAL('triggered()'), self.extract_images)
        self.menuPdf.addAction(self.showPdfImagesAction)
        self.ui.menuEdit.addSeparator()
        self.deleteStoredTextAction = QtGui.QAction(QtGui.QIcon('%strash.png' % self.config_dict['iconLocation']),
                                                    '&Delete stored selections', self)
        self.connect(self.deleteStoredTextAction,
                     QtCore.SIGNAL('triggered()'), self.deleteStoredText)
        self.ui.menuEdit.addAction(self.deleteStoredTextAction)
        self.ui.menuEdit.addSeparator()
        
        self.showAvailableAction = QtGui.QAction(QtGui.QIcon('%sworking.png' %
                                                             self.config_dict['iconLocation']),
                                                    'Show Do&wnloaded', self)
        self.connect(self.showAvailableAction,
                     QtCore.SIGNAL('triggered()'), self.show_downloaded_only)
        self.ui.menuEdit.addAction(self.showAvailableAction)
        self.ui.menuEdit.addSeparator()        
        self.openPrefsAction = QtGui.QAction(QtGui.QIcon('%stoolbox.png' % self.config_dict['iconLocation']),
                                                    '&Open Preferences', self)
        self.connect(self.openPrefsAction,
                     QtCore.SIGNAL('triggered()'), self.open_preferences)
        self.ui.menuEdit.addAction(self.openPrefsAction)
        
        self.aboutAction = QtGui.QAction(QtGui.QIcon('%sCctrl.png' % self.config_dict['iconLocation']),
                                                    '&About Citation Control', self)
        self.connect(self.aboutAction,
                     QtCore.SIGNAL('triggered()'), self.aboutCitationControl)
        self.ui.menuHelp.addAction(self.aboutAction)
        self.helpMenu = QtGui.QMenu("How do I ...")
        self.helpMenu.setIcon(self.help_icon)
        self.ui.menuHelp.addMenu(self.helpMenu)
        self.populate_help_menu()
        
        # Button connections
        self.connect(self.ui.ObtainCiteButton, QtCore.SIGNAL('clicked()'),
                     self.obtain_citations)
        self.connect(self.ui.ObtainRefButton, QtCore.SIGNAL('clicked()'),
                     self.obtain_references)
        self.connect(self.ui.ObtainRelatedButton, QtCore.SIGNAL('clicked()'),
                     self.obtain_related)
        self.connect(self.ui.ObtainFTextButton, QtCore.SIGNAL('clicked()'),
                     self.obtainFTextButton_clicked)
        self.connect(self.ui.scopusSearchButton, QtCore.SIGNAL('clicked()'),
                     self.search_scopus_button_clicked)
        self.connect(self.ui.scopusSearchLineEdit, QtCore.SIGNAL('returnPressed ()'),
                     self.search_scopus_button_clicked)
        self.connect(self.ui.lineEdit, QtCore.SIGNAL('returnPressed ()'),
                     self.fullTextSearch)
        self.connect(self.ui.treeWidget, QtCore.SIGNAL('itemSelectionChanged()'), self.show_selection_status)
        self.ui.treeWidget.itemDoubleClicked.connect(self.item_double_clicked)
        self.connect(self.ui.pushButton, QtCore.SIGNAL('clicked()'),
                     self.fullTextSearch)
        self.connect(self.ui.lineEdit, QtCore.SIGNAL('textChanged (const QString&)'),
                     self.fullTextSearchAuto)
        #Filters
        self.connect(self.ui.TitleFilter, QtCore.SIGNAL('textChanged (const QString&)'),
                     self.filter_title)
        self.connect(self.ui.AuthorFilter, QtCore.SIGNAL('textChanged (const QString&)'),
                     self.filter_author)
        self.connect(self.ui.YearFilter, QtCore.SIGNAL('textChanged (const QString&)'),
                     self.filter_year)
        self.connect(self.ui.JournalFilter, QtCore.SIGNAL('textChanged (const QString&)'),
                     self.filter_journal)
        self.connect(self.ui.TagFilter, QtCore.SIGNAL('textChanged (const QString&)'),
                     self.filter_tag)
        self.create_tag_manager_context_actions()
    
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = StartQT4()
    myapp.showMaximized()
    sys.exit(app.exec_())
